aboutsummaryrefslogtreecommitdiffstats
path: root/src/routes/(app)/[username]/settings
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2024-09-10 20:39:47 -0700
committerAdam Soltys <[email protected]>2024-09-17 09:18:36 -0700
commit1f63848ca9fb01336f04b41434de1cc06a5b3d93 (patch)
tree2affa3041863be365f33d99e1f32bda60cf93a32 /src/routes/(app)/[username]/settings
parent6e48c584605bec5623c12c470d04d07303983801 (diff)
downloadcoinos-ui-1f63848ca9fb01336f04b41434de1cc06a5b3d93.tar.gz
coinos-ui-1f63848ca9fb01336f04b41434de1cc06a5b3d93.zip
move routes
Diffstat (limited to 'src/routes/(app)/[username]/settings')
-rw-r--r--src/routes/(app)/[username]/settings/[...tab]/+page.server.ts34
-rw-r--r--src/routes/(app)/[username]/settings/[...tab]/+page.svelte257
-rw-r--r--src/routes/(app)/[username]/settings/[...tab]/_account.svelte190
-rw-r--r--src/routes/(app)/[username]/settings/[...tab]/_pos.svelte238
-rw-r--r--src/routes/(app)/[username]/settings/[...tab]/_security.svelte321
-rw-r--r--src/routes/(app)/[username]/settings/[...tab]/_shopify.svelte92
6 files changed, 0 insertions, 1132 deletions
diff --git a/src/routes/(app)/[username]/settings/[...tab]/+page.server.ts b/src/routes/(app)/[username]/settings/[...tab]/+page.server.ts
deleted file mode 100644
index 42639b38..00000000
--- a/src/routes/(app)/[username]/settings/[...tab]/+page.server.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import { fail, redirect } from "@sveltejs/kit";
-import { fd, auth, get, post } from "$lib/utils";
-
-export function load({ cookies, params, url }) {
- if (url.pathname.endsWith("settings"))
- redirect(307, url.pathname + "/account");
- params.cookies = cookies.getAll();
- return { cookies: cookies.getAll(), tab: params.tab };
-}
-
-export const actions = {
- default: async ({ cookies, request }) => {
- let form = await fd(request);
-
- if (form.tab === "pos") {
- form.notify = form.notify === "on";
- form.nip5 = form.nip5 === "on";
- form.prompt = form.prompt === "on";
- form.autowithdraw = form.autowithdraw === "on";
- }
-
- let user = { ...(await get("/me", auth(cookies))), ...form };
-
- try {
- ({ user } = await post(`/user`, user, auth(cookies)));
- } catch (e: any) {
- return fail(400, { message: e.message });
- }
-
- if (user.language) cookies.set("lang", user.language, { path: "/" });
-
- return { user, success: true };
- },
-};
diff --git a/src/routes/(app)/[username]/settings/[...tab]/+page.svelte b/src/routes/(app)/[username]/settings/[...tab]/+page.svelte
deleted file mode 100644
index 12980291..00000000
--- a/src/routes/(app)/[username]/settings/[...tab]/+page.svelte
+++ /dev/null
@@ -1,257 +0,0 @@
-<script>
- import { browser } from "$app/environment";
- import { onMount, tick } from "svelte";
- import { fly } from "svelte/transition";
- import { applyAction, deserialize } from "$app/forms";
-
- import Icon from "$comp/Icon.svelte";
- import Spinner from "$comp/Spinner.svelte";
- import Pin from "$comp/Pin.svelte";
- import { loading, t } from "$lib/translations";
- import { fail, auth, post, sleep, warning, success } from "$lib/utils";
- import { avatar, banner, password, pin } from "$lib/store";
- import { upload } from "$lib/upload";
- import { page } from "$app/stores";
- import { sign, send, reEncryptEntropy, setNsec } from "$lib/nostr";
- import { invalidateAll } from "$app/navigation";
-
- import Account from "./_account.svelte";
- import Pos from "./_pos.svelte";
- import Security from "./_security.svelte";
- import Shopify from "./_shopify.svelte";
-
- import { PUBLIC_COINOS_URL } from "$env/static/public";
-
- export let data;
- export let form;
-
- let submit;
- let formElement;
-
- let { user, token, rates, tab, cookies } = data;
- let prev;
-
- $: update(data);
- let update = () => {
- ({ user, token, rates, tab } = data);
- prev = { ...user };
- };
-
- $: form?.user && ({ user } = form);
-
- $: form?.success && throttledSuccess();
-
- let justUpdated;
- let throttledSuccess = () => {
- if (!justUpdated) {
- justUpdated = true;
- success($t("user.settings.saved"), false);
- setTimeout(() => (justUpdated = false), 5000);
- }
- };
-
- $: form?.message && fail(form.message);
-
- $: if (form?.message?.startsWith("Pin")) {
- fail("Wrong pin, try again");
- $pin = "";
- }
-
- let tabs = [
- { name: "account", key: "ACCOUNT", comp: Account },
- { name: "pos", key: "POINT_OF_SALE", comp: Pos },
- { name: "security", key: "SECURITY", comp: Security },
- { name: "shopify", key: "SHOPIFY", comp: Shopify },
- ];
-
- $: ({ comp } = tabs.find((t) => t.name === tab));
-
- let { address, id, username } = user;
- let submitting;
-
- $: if (!$loading && $page.url.searchParams.get("verified"))
- success($t("user.settings.verified"));
-
- async function handleSubmit() {
- try {
- submitting = true;
- let data = new FormData(formElement);
-
- if (data.get("newNsec")) {
- await setNsec(user, data.get("newNsec"));
- data.set("nsec", user.nsec);
- data.set("pubkey", user.pubkey);
- }
-
- if (data.get("password")) {
- try {
- data.set(
- "cipher",
- await reEncryptEntropy(user, data.get("password"))
- );
- } catch (e) {
- console.log("Failed to encrypt keys with new password");
- throw e;
- }
- }
-
- if ($avatar) {
- try {
- let { hash } = JSON.parse(
- await upload($avatar.file, $avatar.type, $avatar.progress, token)
- );
-
- data.set("profile", hash);
-
- await fetch(`/api/public/${hash}.webp`, {
- cache: "reload",
- mode: "no-cors",
- });
- } catch (e) {
- console.log("problem upsubmitting avatar", e);
- }
- }
-
- if ($banner) {
- try {
- let { hash } = JSON.parse(
- await upload($banner.file, $banner.type, $banner.progress, token)
- );
-
- data.set("banner", hash);
-
- await fetch(`/api/public/${hash}.webp`, {
- cache: "reload",
- mode: "no-cors",
- });
- } catch (e) {
- console.log("problem upsubmitting banner", e);
- }
- }
-
- if (["username", "address", "profile"].some((a) => user[a] !== prev[a])) {
- let event = {
- pubkey: user.pubkey,
- created_at: Math.floor(Date.now() / 1000),
- kind: 0,
- content: JSON.stringify({
- name: user.username,
- about: user.address,
- picture: `${PUBLIC_COINOS_URL}/public/${user.profile}.webp`,
- }),
- tags: [],
- };
-
- try {
- await sign({ event, user });
- await send(event);
- } catch (e) {
- warning("Nostr profile could not be updated");
- }
- }
-
- if (user.email !== prev.email) {
- try {
- cookies.get = function (n) {
- return this.find((c) => c.name === n).value;
- };
-
- user.verified = false;
-
- await post(
- "/api/request",
- { id: user.id, email: user.email },
- auth(cookies)
- );
-
- warning($t("user.settings.verifying"), false);
- } catch (e) {
- fail(e.message);
- console.log(e);
- }
- }
-
- const response = await fetch(formElement.action, {
- method: "POST",
- body: data,
- });
-
- const result = deserialize(await response.text());
-
- if (result.type === "success") {
- await invalidateAll();
- if (data.get("password")) $password = data.get("password");
- }
-
- applyAction(result);
- } catch (e) {
- console.log(e);
- fail("Something went wrong");
- }
-
- submitting = false;
- }
-</script>
-
-{#if user.haspin && $pin?.length !== 6}
- <Pin />
-{/if}
-
-<form
- method="POST"
- class="mb-[154px] settings"
- on:submit|preventDefault={handleSubmit}
- bind:this={formElement}
->
- <input type="hidden" name="pin" value={$pin} />
- <input type="hidden" name="tab" value={tab} />
-
- <div class="mt-24 mb-20 px-3 md:px-0 w-full md:w-[400px] mx-auto space-y-8">
- <div class="header">
- <h1 class="text-center text-3xl md:text-4xl font-semibold mb-10">
- {$t("user.settings.header")}
- </h1>
-
- <div
- class="font-bold flex justify-around items-center border-b pb-3 text-secondary"
- >
- {#each tabs.filter((t) => t.name !== "shopify") as { name, key }}
- <a href={`/${user.username}/settings/${name}`}>
- <button
- type="button"
- class="hover:opacity-80"
- class:text-black={tab === name ||
- (tab === "shopify" && name === "pos")}
- >{$t(`user.settings.${key}`)}</button
- >
- </a>
- {/each}
- </div>
- </div>
-
- <svelte:component this={comp} {user} {rates} {submit} />
- </div>
-
- <div
- class="z-10 fixed bottom-0 bg-white shadow border-t w-full flex justify-center items-center py-3"
- >
- <button
- bind:this={submit}
- type="submit"
- class="border-2 border-black rounded-xl font-semibold mx-auto py-3 w-40 hover:opacity-80"
- class:bg-black={submitting}
- >
- {#if submitting}
- <Spinner />
- {:else}
- <div class="my-auto">{$t("user.settings.saveSettings")}</div>
- {/if}
- </button>
- </div>
-</form>
-
-<style>
- .settings {
- view-transition-name: settings;
- }
-</style>
diff --git a/src/routes/(app)/[username]/settings/[...tab]/_account.svelte b/src/routes/(app)/[username]/settings/[...tab]/_account.svelte
deleted file mode 100644
index 8e3323c7..00000000
--- a/src/routes/(app)/[username]/settings/[...tab]/_account.svelte
+++ /dev/null
@@ -1,190 +0,0 @@
-<script>
- import { tick } from "svelte";
- import { avatar, banner } from "$lib/store";
- import Icon from "$comp/Icon.svelte";
- import { t } from "$lib/translations";
- import { page } from "$app/stores";
-
- export let user, rates, submit;
-
- let { id } = user;
-
- let avatarFile, avatarInput, bannerFile, bannerInput;
-
- let selectAvatar = () => avatarInput.click();
- let selectBanner = () => bannerInput.click();
-
- let percent;
- let progress = async (event) => {
- percent = Math.round((event.loaded / event.total) * 100);
- };
-
- let tooLarge = {};
-
- let handleFile = async ({ target }, type) => {
- tooLarge[type] = false;
- let file = target.files[0];
- if (!file) return;
-
- if (file.size > 10000000) return (tooLarge[type] = true);
-
- if (type === "profile") {
- $avatar = { id, file, type, progress };
- } else if (type === "banner") {
- $banner = { id, file, type, progress };
- }
-
- var reader = new FileReader();
- reader.onload = async (e) => {
- if (type === "profile") {
- $avatar.src = e.target.result;
- } else if (type === "banner") {
- $banner.src = e.target.result;
- }
- };
-
- reader.readAsDataURL(file);
- };
-
- if (!user.display) user.display = user.username;
-
- $: url = `${$page.url.host}/${user.username}`;
- $: full = `${$page.url.protocol}//${url}`;
- $: addr = `${user.username}@${$page.url.host}`;
-</script>
-
-<div>
- <label for="username" class="font-bold mb-1 block"
- >{$t("user.settings.username")}</label
- >
- <div class="flex mb-2">
- <input
- type="text"
- name="username"
- bind:value={user.username}
- class="w-auto min-w-0 pr-1 grow"
- />
- </div>
-</div>
-
-<div>
- <label for="display" class="font-bold mb-1 block"
- >{$t("user.settings.displayName")}</label
- >
- <input type="text" name="display" bind:value={user.display} />
-</div>
-
-<div class="space-y-1 relative">
- <label for="email" class="font-bold block">{$t("user.settings.email")}</label>
- <p class="text-secondary">
- {$t("user.settings.emailDescription")}
- </p>
-
- <div class="relative">
- <input type="text" name="email" bind:value={user.email} />
- {#if user.verified}
- <Icon icon="check" style="absolute right-5 top-3 w-8" />
- {:else if user.email}
- <Icon icon="orangeclock" style="absolute right-5 top-3 w-8" />
- {/if}
- </div>
-</div>
-
-<div>
- <span class="font-bold">{$t("user.settings.profileImage")}</span>
-
- <div class="flex">
- {#if $avatar || user.profile}
- <div
- class="relative rounded-full overflow-hidden text-center w-20 h-20 my-auto hover:opacity-80 cursor-pointer"
- on:click={selectAvatar}
- on:keydown={selectAvatar}
- >
- <img
- src={$avatar?.src || `/api/public/${user.profile}.webp`}
- class="absolute w-full h-full object-cover object-center visible overflow-hidden"
- alt={user.username}
- />
- </div>
- {:else}
- <div
- class="rounded-full border-4 border-white p-4 bg-gradient-to-r from-primary to-gradient w-24 my-auto hover:opacity-80 cursor-pointer"
- on:click={selectAvatar}
- on:keydown={selectAvatar}
- >
- <Icon icon="logo-symbol-white" style="mx-auto" />
- </div>
- {/if}
- <div class="ml-2 p-2">
- <!-- found missing translation -->
- <button
- type="button"
- class="border rounded-2xl font-bold w-24 text-center px-0 py-2 hover:opacity-80"
- on:click={selectAvatar}
- on:keydown={selectAvatar}>{$t("user.settings.select")}</button
- >
- <input
- type="file"
- class="hidden"
- bind:this={avatarInput}
- on:change={(e) => handleFile(e, "profile")}
- />
- </div>
- </div>
-
- {#if tooLarge["avatar"]}
- <div class="text-red-600">Max file size 10MB</div>
- {/if}
-</div>
-
-<div>
- <div class="flex justify-between items-center">
- <span class="font-bold">{$t("user.settings.bannerImage")}</span>
- </div>
-
- {#if $banner || user.banner}
- <img
- src={$banner ? $banner.src : `/api/public/${user.banner}.webp`}
- class="w-full object-cover object-center visible overflow-hidden h-48 mb-4 hover:opacity-80"
- on:click={selectBanner}
- on:keydown={selectBanner}
- alt="Banner"
- />
- {:else}
- <div
- class="bg-gradient-to-r from-primary to-gradient w-full h-48 mb-4 cursor-pointer hover:opacity-80"
- on:click={selectBanner}
- on:keydown={selectBanner}
- alt="Banner"
- />
- {/if}
-
- <button
- type="button"
- class="border rounded-2xl font-bold w-24 text-center px-0 py-2 hover:opacity-80"
- on:click={selectBanner}
- on:keydown={selectBanner}>{$t("user.settings.select")}</button
- >
- <input
- type="file"
- class="hidden"
- bind:this={bannerInput}
- on:change={(e) => handleFile(e, "banner")}
- />
-
- {#if tooLarge["banner"]}
- <div class="text-red-600">Max file size 10MB</div>
- {/if}
-</div>
-
-<div>
- <label for="address" class="font-bold mb-1 block"
- >{$t("user.settings.about")}</label
- >
- <textarea
- type="text"
- name="address"
- bind:value={user.address}
- placeholder={$t("user.settings.aboutPlaceholder")}
- />
-</div>
diff --git a/src/routes/(app)/[username]/settings/[...tab]/_pos.svelte b/src/routes/(app)/[username]/settings/[...tab]/_pos.svelte
deleted file mode 100644
index 6a1c92a1..00000000
--- a/src/routes/(app)/[username]/settings/[...tab]/_pos.svelte
+++ /dev/null
@@ -1,238 +0,0 @@
-<script>
- import { tick } from "svelte";
- import Icon from "$comp/Icon.svelte";
- import Numpad from "$comp/Numpad.svelte";
- import LocaleSelector from "$comp/LocaleSelector.svelte";
- import Toggle from "$comp/Toggle.svelte";
- import { locale, t } from "$lib/translations";
- import { success, fail } from "$lib/utils";
- import { page } from "$app/stores";
-
- export let user, rates, submit;
-
- let { currency } = user;
- let rate = rates[currency];
-
- let fiats = Object.keys(rates).sort((a,b) => a.localeCompare(b));
- $: user.language = $locale;
- let keypress = (e) => e.key === "Enter" && (e.preventDefault() || el.click());
-
- let editingReserve, editingThreshold, doneReserve, doneThreshold;
- let doneEditing = () => {
- editingReserve = false;
- editingThreshold = false;
- };
-
- let editReserve = async () => {
- editingReserve = true;
- await tick();
- reserveEl.focus();
- };
-
- let editThreshold = async () => {
- editingThreshold = true;
- await tick();
- thresholdEl.focus();
- };
-
- if (!user.threshold) user.threshold = 1000000;
- if (!user.reserve) user.reserve = 100000;
- let reserveEl, thresholdEl;
-</script>
-
-<div>
- <label for="language" class="font-bold block mb-1"
- >{$t("user.settings.locale")}</label
- >
- <LocaleSelector style="select-styles block py-3 w-full" />
-</div>
-
-<div>
- <label for="currency" class="font-bold block mb-1"
- >{$t("user.settings.localCurrency")}</label
- >
- <select
- name="currency"
- class="select-styles block py-3 w-full"
- value={user.currency}
- >
- {#each fiats as fiat}
- <option value={fiat}>{fiat}</option>
- {/each}
- </select>
-</div>
-
-<div>
- <label for="memoPrompt" class="font-bold mb-1 block"
- >{$t("user.settings.memoPrompt")}</label
- >
- <textarea
- name="memoPrompt"
- placeholder={$t("user.settings.memoPromptPlaceholder")}
- bind:value={user.memoPrompt}
- />
-</div>
-
-<div>
- <div class="flex justify-between items-center">
- <span class="font-bold">{$t("user.settings.notifications")}</span>
- <Toggle id="notify" bind:value={user.notify} />
- </div>
- <p class="text-secondary mt-1 w-9/12">
- {$t("user.settings.notificationsDesc")}
- </p>
-</div>
-
-<div>
- <div class="flex justify-between items-center">
- <span class="font-bold">{$t("user.settings.tipPrompt")}</span>
- <Toggle id="prompt" bind:value={user.prompt} />
- </div>
- <p class="text-secondary mt-1 w-9/12">
- {$t("user.settings.tipPromptDescription")}
- </p>
-</div>
-
-<div>
- <div class="flex justify-between items-center">
- <span class="font-bold">{$t("user.settings.publishNip5")}</span>
- <Toggle id="nip5" bind:value={user.nip5} />
- </div>
- <p class="text-secondary mt-1 w-9/12">
- {$t("user.settings.nip5a")}
- <span class="font-bold">{user.username}@{$page.url.host}</span>
- {$t("user.settings.nip5b")}
- </p>
-</div>
-
-<div>
- <div class="flex justify-between items-center">
- <span class="font-bold">{$t("user.settings.autoWithdraw")}</span>
- <Toggle id="autowithdraw" bind:value={user.autowithdraw} />
- </div>
- <p class="text-secondary mt-1 w-9/12">
- {$t("user.settings.autoWithdrawDescription")}
- </p>
-</div>
-
-{#if user.autowithdraw}
- <div class="mb-2">
- <label for="display" class="font-bold mb-1 block"
- >{$t("user.settings.destination")}</label
- >
- <textarea
- name="destination"
- placeholder={$t("user.settings.destinationPlaceholder")}
- on:keypress={keypress}
- class="w-full p-4 border rounded-xl h-48"
- bind:value={user.destination}
- />
- </div>
-
- <div>
- <label for="display" class="font-bold mb-1 block"
- >{$t("user.settings.threshold")}</label
- >
- <button type="button" class="flex w-full" on:click={editThreshold}>
- <div class="p-4 border rounded-2xl rounded-r-none border-r-0 bg-primary">
- ⚡️
- </div>
- <div
- class="border-l-0 rounded-l-none pl-2 w-full p-4 border rounded-2xl text-left"
- >
- {user.threshold}
- </div>
- <input type="hidden" name="threshold" bind:value={user.threshold} />
- </button>
- <p class="text-secondary mt-1">
- {$t("user.settings.thresholdDesc")}
- </p>
- </div>
-
- <div>
- <label for="display" class="font-bold mb-1 block"
- >{$t("user.settings.reserve")}</label
- >
- <button type="button" class="flex w-full" on:click={editReserve}>
- <div class="p-4 border rounded-2xl rounded-r-none border-r-0 bg-primary">
- ⚡️
- </div>
- <div
- class="border-l-0 rounded-l-none pl-2 w-full p-4 border rounded-2xl text-left"
- >
- {user.reserve}
- </div>
- <input type="hidden" name="reserve" bind:value={user.reserve} />
- </button>
- <p class="text-secondary mt-1">
- {$t("user.settings.reserveDesc")}
- </p>
- </div>
-{/if}
-
-{#if editingThreshold}
- <div
- class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50"
- >
- <div
- class="relative top-40 mx-auto p-5 border shadow-lg rounded-md bg-white space-y-5 w-lg max-w-lg"
- >
- <h1 class="text-center text-2xl font-semibold">
- {$t("user.settings.threshold")}
- </h1>
- <Numpad
- bind:amount={user.threshold}
- bind:currency
- bind:rate
- bind:submit={doneReserve}
- bind:element={thresholdEl}
- />
-
- <button
- bind:this={doneReserve}
- type="button"
- on:click={doneEditing}
- class="p-4 bg-black text-white rounded-2xl text-lg font-semibold w-full"
- >Ok</button
- >
- </div>
- </div>
-{/if}
-
-{#if editingReserve}
- <div
- class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50"
- >
- <div
- class="relative top-40 mx-auto p-5 border shadow-lg rounded-md bg-white space-y-5 w-lg max-w-lg text-center"
- >
- <h1 class="text-2xl font-semibold">
- {$t("user.settings.reserve")}
- </h1>
- <Numpad
- bind:amount={user.reserve}
- bind:currency
- bind:rate
- bind:submit={doneReserve}
- bind:element={reserveEl}
- />
- <button
- bind:this={doneReserve}
- type="button"
- on:click={doneEditing}
- class="p-4 bg-black text-white rounded-2xl text-lg font-semibold w-full"
- >Ok</button
- >
- </div>
- </div>
-{/if}
-
-<a href="./shopify">
- <button
- type="button"
- class="flex rounded-full border py-2 px-4 font-bold hover:opacity-80 w-full gap-2 my-5 justify-center"
- >
- <img src="/icons/shopify.svg" class="w-8" />
- <div class="my-auto">{$t("user.settings.shopify")}</div>
- </button>
-</a>
diff --git a/src/routes/(app)/[username]/settings/[...tab]/_security.svelte b/src/routes/(app)/[username]/settings/[...tab]/_security.svelte
deleted file mode 100644
index 6b44f830..00000000
--- a/src/routes/(app)/[username]/settings/[...tab]/_security.svelte
+++ /dev/null
@@ -1,321 +0,0 @@
-<script>
- import { getMnemonic, getNsec } from "$lib/nostr";
- import { tick } from "svelte";
- import { t } from "$lib/translations";
- import Pin from "$comp/Pin.svelte";
- import Icon from "$comp/Icon.svelte";
- import Qr from "$comp/Qr.svelte";
- import { copy, post, success, fail } from "$lib/utils";
- import { pin as current } from "$lib/store";
- import { invalidate } from "$app/navigation";
- import { page } from "$app/stores";
-
- export let user, rates, submit;
-
- let confirming2fa,
- disabling2fa,
- importing,
- locked,
- mnemonic,
- newNsec,
- nsec,
- old,
- otp,
- password,
- pin,
- revealPassword,
- revealSeed,
- revealNsec,
- token = "",
- setting2fa,
- settingPin,
- verify;
-
- let toggleImporting = () => {
- revealNsec = false;
- importing = !importing;
- };
-
- let toggleNsec = async () => {
- try {
- nsec = await getNsec(user);
- revealNsec = !revealNsec;
- importing = false;
- } catch (e) {
- console.log(e);
- }
- };
-
- let togglePassword = () => (revealPassword = !revealPassword);
- let toggleSeed = async () => {
- try {
- mnemonic = await getMnemonic(user);
- revealSeed = !revealSeed;
- } catch (e) {
- console.log(e);
- }
- };
-
- $: verifying = pin?.length > 5;
- $: verify && checkPin(pin);
- let checkPin = async () => {
- old = $current;
-
- try {
- if (pin.length > 5 && pin === verify) {
- user.haspin = true;
- $current = pin;
- pin = "";
- verify = "";
- submit.click();
- settingPin = false;
- verifying = false;
- } else {
- fail("Pin mismatch, try again");
- pin = "";
- verify = "";
- verifying = false;
- settingPin = true;
- }
- } catch (e) {
- console.log(e);
- fail("Problem setting PIN");
- }
- };
-
- let reset = () => {
- token = "";
- return true;
- };
-
- let disablingPin = false;
-
- let togglePin = async () => {
- if (user.haspin) {
- try {
- disablingPin = true;
- await tick();
- submit.click();
- } catch (e) {
- console.log(e);
- fail("Failed to disable pin");
- }
- } else {
- settingPin = true;
- disablingPin = false;
- }
- };
-
- let startEnabling2fa = async () => {
- reset();
- try {
- if (!otp) otp = await post("/otpsecret", { pin: $current });
- } catch (e) {
- console.log(e);
- }
-
- setting2fa = true;
- };
-
- let startDisabling2fa = () => (disabling2fa = true);
- let startConfirming2fa = () => (confirming2fa = true);
- let cancel = () => {
- pin = null;
- token = null;
- verifying = false;
- settingPin = false;
- setting2fa = false;
- confirming2fa = false;
- disabling2fa = false;
- };
-
- $: enable2fa(token);
- let enable2fa = async (twoFa) => {
- try {
- if (setting2fa && token.length === 6) {
- await post("/enable2fa", { token });
- success("2FA enabled");
- user.twofa = 1;
- cancel();
- }
- } catch (e) {
- fail("Failed to enable 2FA, try again");
- }
- };
-
- $: disable2fa(token);
- let disable2fa = async () => {
- try {
- if (disabling2fa && token.length === 6) {
- await post("/disable2fa", { token });
- success("2FA disabled");
- delete user.twofa;
- disabling2fa = false;
- }
- } catch (e) {
- console.log(e);
- fail("Failed to disable 2FA, try again");
- }
- };
-</script>
-
-<input type="hidden" name="newpin" value={disablingPin ? "delete" : pin} />
-<input type="hidden" name="confirm" bind:value={password} />
-
-<div class="relative mb-5">
- <label for="password" class="block font-bold block mb-1"
- >{$t("user.settings.newPassword")}</label
- >
- {#if revealPassword}
- <input name="password" type="text" bind:value={password} />
- {:else}
- <input name="password" type="password" bind:value={password} />
- {/if}
- <button
- type="button"
- on:click={togglePassword}
- on:keydown={togglePassword}
- class="absolute right-5 top-11"
- >
- <Icon icon={revealPassword ? "eye" : "eye-off"} />
- </button>
-</div>
-
-<div>
- <span class="font-bold mb-1"
- >{verifying
- ? $t("user.settings.verifyPIN")
- : $t("user.settings.securityPIN")}</span
- >
- <p class="text-secondary mb-1">
- {$t("user.settings.securityPINDescription")}
- </p>
- {#if verifying}
- <Pin bind:value={verify} {cancel} notify={false} />
- {:else if settingPin}
- <Pin
- bind:value={pin}
- title={$t("user.settings.setPIN")}
- {cancel}
- notify={false}
- />
- {:else}
- <button type="button" class="primary" on:click={togglePin}
- ><Icon icon="lock" style="mr-1" />
- {user.haspin
- ? $t("user.settings.disablePIN")
- : $t("user.settings.enablePIN")}</button
- >
- {/if}
-</div>
-
-<div>
- <span class="font-bold mb-1">{$t("user.settings.twofa")}</span>
- <p class="text-secondary mb-4">
- {$t("user.settings.twofaDescription")}
- </p>
-
- {#if setting2fa}
- <a href={otp.uri}>
- <Qr src={otp.qr} />
- </a>
-
- <div class="text-center my-4">
- {$t("user.settings.accountId")}<br />
- <b>{otp.secret}</b>
- </div>
-
- <button type="button" class="primary" on:click={startConfirming2fa}>
- <Icon icon="numpad" style="w-8 mr-1" />
- <div class="my-auto">Confirm</div>
- </button>
- {:else if user.twofa}
- <button type="button" class="primary" on:click={startDisabling2fa}>
- <Icon icon="mobile" style="w-8 mr-1" />
- <div class="my-auto">{$t("user.settings.twofaDisable")}</div>
- </button>
- {:else}
- <button type="button" class="primary" on:click={startEnabling2fa}>
- <Icon icon="mobile" style="w-8 mr-1" />
- <div class="my-auto">{$t("user.settings.twofaSetup")}</div>
- </button>
- {/if}
-
- {#if confirming2fa || disabling2fa}
- <Pin
- bind:value={token}
- title="Enter 2FA Code"
- {cancel}
- persist={false}
- notify={false}
- />
- {/if}
-</div>
-
-<!-- <div> -->
-<!-- <label for="seedphrase" class="font-bold" -->
-<!-- >{$t("user.settings.seedPhrase")}</label -->
-<!-- > -->
-<!-- -->
-<!-- <p class="text-secondary mb-1"> -->
-<!-- {$t("user.settings.seedDescription")} -->
-<!-- </p> -->
-<!-- -->
-<!-- <button type="button" class="primary" on:click={toggleSeed}> -->
-<!-- <Icon icon="warning" style="mr-1 w-6 my-auto" /> -->
-<!-- {revealSeed ? $t("user.settings.hideSeed") : $t("user.settings.revealSeed")} -->
-<!-- </button> -->
-<!-- -->
-<!-- {#if revealSeed} -->
-<!-- <div class="text-lg"> -->
-<!-- {mnemonic} -->
-<!-- </div> -->
-<!-- -->
-<!-- <button type="button" class="primary" on:click={() => copy(mnemonic)}> -->
-<!-- <Icon icon="copy" style="mr-1 w-6 my-auto" /> -->
-<!-- Copy -->
-<!-- </button> -->
-<!-- {/if} -->
-<!-- </div> -->
-
-<div>
- <label for="seedphrase" class="font-bold"
- >{$t("user.settings.nostrKeys")}</label
- >
-
- <p class="text-secondary mb-1">
- {$t("user.settings.nostrDescription")}
- </p>
-
- <div class="flex">
- <button type="button" class="primary" on:click={toggleNsec}>
- {#if revealNsec}
- <Icon icon="eye-off" style="mr-1 w-6 my-auto" />
- {$t("user.settings.hideNsec")}
- {:else}
- <Icon icon="warning" style="mr-1 w-6 my-auto" />
- {$t("user.settings.revealNsec")}
- {/if}
- </button>
-
- <button type="button" class="primary" on:click={toggleImporting}>
- <Icon icon="save" style="mr-1 w-6 my-auto" />
- {$t("user.settings.import")}
- </button>
- </div>
-
- {#if importing}
- <input name="newNsec" bind:value={newNsec} placeholder="nsec..." />
- {/if}
-
- {#if revealNsec}
- <div class="text-lg break-all">
- {nsec}
- </div>
-
- <button type="button" class="primary" on:click={() => copy(nsec)}>
- <Icon icon="copy" style="mr-1 w-6 my-auto" />
- Copy
- </button>
- {/if}
-</div>
diff --git a/src/routes/(app)/[username]/settings/[...tab]/_shopify.svelte b/src/routes/(app)/[username]/settings/[...tab]/_shopify.svelte
deleted file mode 100644
index 0266fa9c..00000000
--- a/src/routes/(app)/[username]/settings/[...tab]/_shopify.svelte
+++ /dev/null
@@ -1,92 +0,0 @@
-<script>
- import { t } from "$lib/translations";
- import Icon from "$comp/Icon.svelte";
- import { page } from "$app/stores";
-
- export let user;
- $: paymentsUrl =
- user.shopifyStore &&
- "https://admin.shopify.com/store/" +
- user.shopifyStore +
- "/settings/payments";
- $: checkoutUrl =
- user.shopifyStore &&
- "https://admin.shopify.com/store/" +
- user.shopifyStore +
- "/settings/checkout";
- $: appsUrl =
- user.shopifyStore &&
- "https://admin.shopify.com/store/" +
- user.shopifyStore +
- "/settings/apps/development";
-
- let script = `<script src="${$page.url.protocol}//${$page.url.host}/${user.username}/shopify.js"><\/script>`;
-</script>
-
-<div>
- <label for="shopifyStore" class="font-bold mb-1 block">Store ID</label>
- <div class="flex mb-2">
- <div
- class="text-gray-600 p-4 my-auto bg-gray-100 border rounded-l-2xl border-r-0 pr-1"
- >
- admin.shopify.com/store/
- </div>
- <input
- type="text"
- name="shopifyStore"
- bind:value={user.shopifyStore}
- class="border-l-0 rounded-l-none w-auto min-w-0 pl-1 grow"
- />
- </div>
- <p class="text-secondary my-2">
- Add Bitcoin under <a
- class:active={!!paymentsUrl}
- href={paymentsUrl || undefined}>Payments > Manual payment methods</a
- > with a description like "Pay with Bitcoin".
- </p>
-</div>
-
-<div>
- <label for="display" class="font-bold mb-1 block">Additional scripts</label>
- <p class="text-secondary my-2">
- Copy this into <a class:active={!!paymentsUrl} href={checkoutUrl}
- >Checkout -> Additional scripts</a
- >
- </p>
- <textarea rows={5} type="text" name="shopifyScripts" readonly
- >{script}</textarea
- >
-</div>
-
-<div>
- <label for="shopifyToken" class="font-bold mb-1 block"
- >Admin API token <span class="font-normal">(Optional)</span></label
- >
- <p class="text-secondary my-2">
- Coinos can automatically mark orders as Paid if you provide an API token.
- <input
- class="my-4"
- type="text"
- name="shopifyToken"
- bind:value={user.shopifyToken}
- />
- </p>
- <p class="text-secondary my-2">
- Create a new app in <a class:active={!!appsUrl} href={appsUrl || undefined}
- >Apps > App Development</a
- >
- </p>
-
- <p class="text-secondary my-2">
- Edit the Admin API scopes to enable <code class="text-black"
- >write_orders</code
- > permission then install the app into your store and copy the Admin API access
- token here.
- </p>
-</div>
-
-<style>
- .active {
- @apply text-blue-500;
- }
-</style>